import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
import { compareJSON, calculateStats, pathToString, formatValue } from '../utils/jsonDiff';
import '../styles/JsonDiffViewer.css';

interface JsonDiffViewerProps {
  oldObject: any;
  newObject: any;
}

interface JsonLineData {
  id: string;
  path: string[];
  displayPath: string;
  type: 'added' | 'removed' | 'modified' | 'moved' | 'unchanged';
  oldValue?: any;
  newValue?: any;
  depth: number;
  isExpandable: boolean;
  isExpanded: boolean;
  oldIndex?: number;
  newIndex?: number;
  lineType?: 'property' | 'objectStart' | 'objectEnd' | 'arrayStart' | 'arrayEnd';
  propertyKey?: string;
}

const JsonDiffViewer: React.FC<JsonDiffViewerProps> = ({ oldObject, newObject }) => {
  const [viewMode, setViewMode] = useState<'side-by-side' | 'unified'>('side-by-side');
  const [expandedPaths, setExpandedPaths] = useState<Set<string>>(new Set());
  // 添加筛选状态，默认全部选中
  const [visibleTypes, setVisibleTypes] = useState<Set<string>>(
    new Set(['unchanged', 'modified', 'added', 'removed', 'moved'])
  );
  // 添加hover和排序状态
  const [hoveredLineId, setHoveredLineId] = useState<string | null>(null);
  const [sortOptions, setSortOptions] = useState<Map<string, 'alternate' | 'oldValue' | 'newValue'>>(new Map());
  
  // 同步滚动refs
  const leftPanelRef = useRef<HTMLDivElement>(null);
  const rightPanelRef = useRef<HTMLDivElement>(null);
  const syncingRef = useRef<boolean>(false);

  // 计算差异
  const diffs = useMemo(() => {
    return compareJSON(oldObject, newObject);
  }, [oldObject, newObject]);

  // 计算统计信息
  const stats = useMemo(() => {
    return calculateStats(diffs);
  }, [diffs]);

  // 计算行号宽度
  const lineNumberWidth = useMemo(() => {
    const totalLines = diffs.length;
    const digits = totalLines.toString().length;
    return Math.max(3, digits) * 8; // 每位数8px + 16px padding
  }, [diffs.length]);

  // 处理展开/折叠
  const toggleExpand = (pathStr: string) => {
    const newExpanded = new Set(expandedPaths);
    if (newExpanded.has(pathStr)) {
      newExpanded.delete(pathStr);
    } else {
      newExpanded.add(pathStr);
    }
    setExpandedPaths(newExpanded);
  };

  // 处理类型筛选切换
  const toggleVisibleType = (type: string) => {
    const newVisibleTypes = new Set(visibleTypes);
    if (newVisibleTypes.has(type)) {
      newVisibleTypes.delete(type);
    } else {
      newVisibleTypes.add(type);
    }
    setVisibleTypes(newVisibleTypes);
  };

  // 处理排序选项变更
  const handleSortOptionChange = (lineId: string, option: 'alternate' | 'oldValue' | 'newValue') => {
    const newSortOptions = new Map(sortOptions);
    newSortOptions.set(lineId, option);
    setSortOptions(newSortOptions);
  };

  // 递归生成树形结构的行数据
  const generateTreeLines = useCallback((
    diff: any,
    depth: number = 0,
    parentExpanded: boolean = true
  ): JsonLineData[] => {
    const lines: JsonLineData[] = [];
    const pathStr = pathToString(diff.path);
    const value = diff.newValue !== undefined ? diff.newValue : diff.oldValue;
    const isExpanded = expandedPaths.has(pathStr);
    const isObject = value && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);
    const isArray = Array.isArray(value);

    if (!parentExpanded) return lines;

    if (isObject) {
      // 对象开始行：objectName {
      lines.push({
        id: `${pathStr}-start`,
        path: diff.path,
        displayPath: diff.path[diff.path.length - 1] || 'root',
        type: diff.type,
        oldValue: diff.oldValue,
        newValue: diff.newValue,
        depth,
        isExpandable: true,
        isExpanded,
        lineType: 'objectStart'
      });

      // 如果展开，显示属性
      if (isExpanded) {
        // 合并新旧对象的所有键，确保不遗漏任何属性
        const oldObj = diff.oldValue || {};
        const newObj = diff.newValue || {};
        let allKeys = [...new Set([...Object.keys(oldObj), ...Object.keys(newObj)])];
        
        // 根据排序选项对键进行排序
        const sortOption = sortOptions.get(`${pathStr}-start`) || 'alternate';
        if (sortOption === 'oldValue') {
          // 按旧值排序：保持旧对象的原始定义顺序
          const oldKeys = Object.keys(oldObj || {});
          const newOnlyKeys = Object.keys(newObj || {}).filter(key => !(key in (oldObj || {})));
          allKeys = [...oldKeys, ...newOnlyKeys];
        } else if (sortOption === 'newValue') {
          // 按新值排序：保持新对象的原始定义顺序
          const newKeys = Object.keys(newObj || {});
          const oldOnlyKeys = Object.keys(oldObj || {}).filter(key => !(key in (newObj || {})));
          allKeys = [...newKeys, ...oldOnlyKeys];
        } else if (sortOption === 'alternate') {
          // 新旧值交替：合并两个对象的原始定义顺序
          const oldKeys = Object.keys(oldObj || {});
          const newKeys = Object.keys(newObj || {});
          
          // 以旧对象的顺序为基础
          const mergedKeys = [...oldKeys];
          
          // 添加只在新对象中出现的键，保持它们在新对象中的相对顺序
          newKeys.forEach(key => {
            if (!mergedKeys.includes(key)) {
              mergedKeys.push(key);
            }
          });
          
          allKeys = mergedKeys;
        }
        
        allKeys.forEach(key => {
          const childValue = newObj[key] !== undefined ? newObj[key] : oldObj[key];
          const childPath = [...diff.path, key];
          const childPathStr = pathToString(childPath);
          
          // 查找这个属性的差异信息
          const oldChildValue = oldObj[key];
          const newChildValue = newObj[key];
          const childDiff = diffs.find(d => pathToString(d.path) === childPathStr) || {
            path: childPath,
            type: (oldChildValue !== undefined && newChildValue === undefined) ? 'removed' as const :
                  (oldChildValue === undefined && newChildValue !== undefined) ? 'added' as const :
                  'unchanged' as const,
            oldValue: oldChildValue,
            newValue: newChildValue
          };

          if (childValue && typeof childValue === 'object' && !(childValue instanceof Date)) {
            // 递归处理嵌套对象/数组
            const childLines = generateTreeLines(childDiff, depth + 1, true);
            lines.push(...childLines);
          } else {
            // 普通属性
            lines.push({
              id: `${childPathStr}-prop`,
              path: childPath,
              displayPath: key,
              type: childDiff.type,
              oldValue: childDiff.oldValue,
              newValue: childDiff.newValue,
              depth: depth + 1,
              isExpandable: false,
              isExpanded: false,
              lineType: 'property',
              propertyKey: key
            });
          }
        });
      }

      // 对象结束行：}
      if (isExpanded) {
        lines.push({
          id: `${pathStr}-end`,
          path: diff.path,
          displayPath: '}',
          type: diff.type,
          oldValue: diff.oldValue,
          newValue: diff.newValue,
          depth,
          isExpandable: false,
          isExpanded: false,
          lineType: 'objectEnd'
        });
      }
    } else if (isArray) {
      // 数组开始行：arrayName [
      lines.push({
        id: `${pathStr}-start`,
        path: diff.path,
        displayPath: diff.path[diff.path.length - 1] || 'root',
        type: diff.type,
        oldValue: diff.oldValue,
        newValue: diff.newValue,
        depth,
        isExpandable: true,
        isExpanded,
        lineType: 'arrayStart'
      });

      // 如果展开，显示数组元素
      if (isExpanded) {
        // 使用更长的数组来确保显示所有元素
        const oldArray = Array.isArray(diff.oldValue) ? diff.oldValue : [];
        const newArray = Array.isArray(diff.newValue) ? diff.newValue : [];
                // 根据排序选项决定数组元素的显示顺序
        const sortOption = sortOptions.get(`${pathStr}-start`) || 'oldValue';
        let arrayToDisplay: any[] = [];
        
        if (sortOption === 'oldValue') {
          // 按旧值排序：直接使用旧数组的顺序，然后添加新数组中独有的元素
          arrayToDisplay = [...oldArray];
          newArray.forEach((element: any) => {
            if (!oldArray.includes(element)) {
              arrayToDisplay.push(element);
            }
          });
        } else if (sortOption === 'newValue') {
          // 按新值排序：直接使用新数组的顺序，然后添加旧数组中独有的元素
          arrayToDisplay = [...newArray];
          oldArray.forEach((element: any) => {
            if (!newArray.includes(element)) {
              arrayToDisplay.push(element);
            }
          });
        } else {
          // 默认按索引顺序
          const maxLength = Math.max(oldArray.length, newArray.length);
          for (let i = 0; i < maxLength; i++) {
            const element = i < newArray.length ? newArray[i] : oldArray[i];
            arrayToDisplay.push(element);
          }
        }
        
        for (let i = 0; i < arrayToDisplay.length; i++) {
          const element = arrayToDisplay[i];
          const childPath = [...diff.path, i.toString()];
          const childPathStr = pathToString(childPath);
          
          // 确定这个元素在新旧数组中的情况
          const oldIndex = oldArray.indexOf(element);
          const newIndex = newArray.indexOf(element);
          
          const oldArrayItem = oldIndex !== -1 ? element : undefined;
          const newArrayItem = newIndex !== -1 ? element : undefined;
          
          // 查找这个元素的差异信息，但优先使用真实的数组值
          const foundDiff = diffs.find(d => pathToString(d.path) === childPathStr);
          
          // 确定差异类型
          let diffType: 'added' | 'removed' | 'modified' | 'moved' | 'unchanged';
          if (oldArrayItem === undefined && newArrayItem !== undefined) {
            diffType = 'added';
          } else if (oldArrayItem !== undefined && newArrayItem === undefined) {
            diffType = 'removed';
          } else if (oldArrayItem !== newArrayItem) {
            diffType = 'modified';
          } else {
            diffType = foundDiff?.type || 'unchanged';
          }
          
          const childDiff = {
            path: childPath,
            type: diffType,
            oldValue: oldArrayItem,
            newValue: newArrayItem,
            oldIndex: foundDiff?.oldIndex,
            newIndex: foundDiff?.newIndex
          };

          const item = newArrayItem !== undefined ? newArrayItem : oldArrayItem;
          
          if (item && typeof item === 'object' && !(item instanceof Date)) {
            // 递归处理嵌套对象/数组
            const childLines = generateTreeLines(childDiff, depth + 1, true);
            lines.push(...childLines);
          } else {
            // 普通元素
            lines.push({
              id: `${childPathStr}-prop`,
              path: childPath,
              displayPath: `[${i}]`,
              type: childDiff.type,
              oldValue: childDiff.oldValue,
              newValue: childDiff.newValue,
              depth: depth + 1,
              isExpandable: false,
              isExpanded: false,
              lineType: 'property',
              propertyKey: i.toString()
            });
          }
        }
      }

      // 数组结束行：]
      if (isExpanded) {
        lines.push({
          id: `${pathStr}-end`,
          path: diff.path,
          displayPath: ']',
          type: diff.type,
          oldValue: diff.oldValue,
          newValue: diff.newValue,
          depth,
          isExpandable: false,
          isExpanded: false,
          lineType: 'arrayEnd'
        });
      }
    } else {
      // 普通值
      lines.push({
        id: `${pathStr}-prop`,
        path: diff.path,
        displayPath: pathStr,
        type: diff.type,
        oldValue: diff.oldValue,
        newValue: diff.newValue,
        depth,
        isExpandable: false,
        isExpanded: false,
        lineType: 'property'
      });
    }

    return lines;
  }, [diffs, expandedPaths, sortOptions]);

  // 将差异结果转换为显示行数据
  const processedLines = useMemo(() => {
    const lines: JsonLineData[] = [];
    
    // 构建根级别的完整结构，按原始定义顺序
    const getAllRootKeys = (): string[] => {
      const oldKeys = Object.keys(oldObject || {});
      const newKeys = Object.keys(newObject || {});
      
      // 以旧对象的顺序为基础（类似alternate模式）
      const mergedKeys = [...oldKeys];
      
      // 添加只在新对象中出现的键，保持它们在新对象中的相对顺序
      newKeys.forEach(key => {
        if (!mergedKeys.includes(key)) {
          mergedKeys.push(key);
        }
      });
      
      return mergedKeys;
    };
    
    const rootKeys = getAllRootKeys();
    
    rootKeys.forEach(key => {
      // 为每个根属性创建或查找差异信息
      const rootDiff = diffs.find(d => d.path.length === 1 && d.path[0] === key) || {
        path: [key],
        type: (oldObject?.[key] !== undefined && newObject?.[key] === undefined) ? 'removed' as const :
              (oldObject?.[key] === undefined && newObject?.[key] !== undefined) ? 'added' as const :
              'unchanged' as const,
        oldValue: oldObject?.[key],
        newValue: newObject?.[key]
      };
      
      const treeLines = generateTreeLines(rootDiff, 0, true);
      lines.push(...treeLines);
    });

    // 根据选中的类型进行筛选
    return lines.filter(line => visibleTypes.has(line.type));
  }, [diffs, expandedPaths, oldObject, newObject, generateTreeLines, visibleTypes, sortOptions]);

  // 获取值的类型用于样式
  const getValueTypeClass = (value: any): string => {
    if (value === null) return 'null';
    if (value === undefined) return 'undefined';
    if (typeof value === 'string') return 'string';
    if (typeof value === 'number') return 'number';
    if (typeof value === 'boolean') return 'boolean';
    return 'object';
  };

  // 计算缩进（只用于行内容）
  const getContentIndentStyle = (depth: number) => {
    const baseIndent = 0; // 基础缩进
    const indentPerLevel = 20; // 每层缩进20px
    return {
      paddingLeft: `${baseIndent + depth * indentPerLevel}px`
    };
  };

  // 将英文差异类型转换为中文
  const getDiffTypeText = (type: string): string => {
    const typeMap: { [key: string]: string } = {
      'unchanged': '\u3000\u3000',
      'modified': '修改',
      'added': '新增',
      'removed': '删除',
      'moved': '移动'
    };
    return typeMap[type] || type;
  };

  // 渲染排序选项框
  const renderSortOptions = (line: JsonLineData, side?: 'old' | 'new') => {
    // 只对对象和数组显示排序选项
    if ((line.lineType !== 'objectStart' && line.lineType !== 'arrayStart') || hoveredLineId !== line.id) return null;
    
    const isArray = line.lineType === 'arrayStart';
    const currentOption = sortOptions.get(line.id) || (isArray ? 'oldValue' : 'alternate');
    const uniqueName = `sort-${line.id}-${side || 'unified'}`;
    
    return (
      <div className="sort-options">
        {/* 对象显示三个选项，数组只显示两个选项 */}
        {!isArray && (
          <label>
            <input
              type="radio"
              name={uniqueName}
              value="alternate"
              checked={currentOption === 'alternate'}
              onChange={() => handleSortOptionChange(line.id, 'alternate')}
            />
            新旧值交替
          </label>
        )}
        <label>
          <input
            type="radio"
            name={uniqueName}
            value="oldValue"
            checked={currentOption === 'oldValue'}
            onChange={() => handleSortOptionChange(line.id, 'oldValue')}
          />
          按旧值排序
        </label>
        <label>
          <input
            type="radio"
            name={uniqueName}
            value="newValue"
            checked={currentOption === 'newValue'}
            onChange={() => handleSortOptionChange(line.id, 'newValue')}
          />
          按新值排序
        </label>
      </div>
    );
  };

  // 渲染单行JSON数据
  const renderJsonLine = (line: JsonLineData, lineNumber: number, side?: 'old' | 'new') => {
    const value = side === 'old' ? line.oldValue : (side === 'new' ? line.newValue : line.newValue !== undefined ? line.newValue : line.oldValue);
    
    // 修复：基于差异类型判断是否应该在某一侧显示，而不是基于值是否为undefined
    // undefined也是一个有效的值，应该正常显示
    const shouldShowInSide = () => {
      if (side === 'old') {
        // 在旧值侧：added类型不显示（因为旧值中没有这个属性）
        return line.type !== 'added';
      } else if (side === 'new') {
        // 在新值侧：removed类型不显示（因为新值中没有这个属性）
        return line.type !== 'removed';
      }
      return true; // 统一视图总是显示
    };
    
    if (!shouldShowInSide() && viewMode === 'side-by-side') {
      return (
        <div 
          key={`${line.id}-${side}`} 
          className="json-line unchanged"
          onMouseEnter={() => setHoveredLineId(line.id)}
          onMouseLeave={() => setHoveredLineId(null)}
        >
          <span 
            className="line-number"
            style={{ width: `${lineNumberWidth}px` }}
          >
            {lineNumber}
          </span>
          <div className="line-content" style={getContentIndentStyle(line.depth)}></div>
        </div>
      );
    }

    // 根据行类型渲染不同内容
    const renderLineContent = () => {
      switch (line.lineType) {
        case 'objectStart':
          return (
            <div className="field-container">
              <div className="expand-toggle-container">
                <button 
                  className={`expand-toggle ${line.isExpanded ? 'expanded' : 'collapsed'}`}
                  onClick={() => toggleExpand(pathToString(line.path))}
                />
              </div>
              <span className="path">{line.displayPath} {line.isExpanded ? '{' : '{ ... }'}</span>
              {renderSortOptions(line, side)}
            </div>
          );
        
        case 'objectEnd':
          return <span className="bracket">{'}'}</span>;
        
        case 'arrayStart':
          return (
            <div className="field-container">
              <div className="expand-toggle-container">
                <button 
                  className={`expand-toggle ${line.isExpanded ? 'expanded' : 'collapsed'}`}
                  onClick={() => toggleExpand(pathToString(line.path))}
                />
              </div>
              <span className="path">{line.displayPath} {line.isExpanded ? '[' : '[ ... ]'}</span>
              {renderSortOptions(line, side)}
            </div>
          );
        
        case 'arrayEnd':
          return <span className="bracket">{']'}</span>;
        
        case 'property':
        default:
          return (
            <div className="field-container">
              <div className="expand-toggle-container">
                <span className="expand-toggle-placeholder"></span>
              </div>
              <span className="path">{line.displayPath}:</span>
              {/* 统一视图中的modified类型显示旧值→新值 */}
              {viewMode === 'unified' && line.type === 'modified' ? (
                <div className="value-change">
                  <span className={`value old-value ${getValueTypeClass(line.oldValue)}`}>
                    {formatValue(line.oldValue)}
                  </span>
                  <span className="change-arrow">→</span>
                  <span className={`value new-value ${getValueTypeClass(line.newValue)}`}>
                    {formatValue(line.newValue)}
                  </span>
                </div>
              ) : (
                <span className={`value ${getValueTypeClass(value)}`}>
                  {formatValue(value)}
                </span>
              )}
              {line.type === 'moved' && (
                <span className="move-indicator">
                  移动: {line.oldIndex} → {line.newIndex}
                </span>
              )}
            </div>
          );
      }
    };

    return (
      <div 
        key={`${line.id}-${side || 'unified'}`} 
        className={`json-line ${line.type}`}
        onMouseEnter={() => setHoveredLineId(line.id)}
        onMouseLeave={() => setHoveredLineId(null)}
      >
        <span 
          className="line-number"
          style={{ width: `${lineNumberWidth}px` }}
        >
          {lineNumber}
        </span>
        <div className="line-content" style={getContentIndentStyle(line.depth)}>
          {viewMode === 'unified' && (
            <span className={`diff-type ${line.type}`}>
              {getDiffTypeText(line.type)}
            </span>
          )}
          
          {renderLineContent()}
        </div>
      </div>
    );
  };

  // 渲染统计信息
  const renderStats = () => (
    <div className="diff-stats">
      <button 
        className="toggle-view-btn"
        onClick={() => setViewMode(viewMode === 'side-by-side' ? 'unified' : 'side-by-side')}
      >
        切换到{viewMode === 'side-by-side' ? '统一视图' : '侧边视图'}
      </button>
      
      <div 
        className={`stats-item unchanged ${visibleTypes.has('unchanged') ? 'checked' : 'unchecked'}`}
        onClick={() => toggleVisibleType('unchanged')}
        style={{ cursor: 'pointer' }}
      >
        <div className="icon"></div>
        <span>不变 · {stats.unchanged}</span>
      </div>
      
      <div 
        className={`stats-item modified ${visibleTypes.has('modified') ? 'checked' : 'unchecked'}`}
        onClick={() => toggleVisibleType('modified')}
        style={{ cursor: 'pointer' }}
      >
        <div className="icon"></div>
        <span>修改 · {stats.modified}</span>
      </div>
      
      <div 
        className={`stats-item added ${visibleTypes.has('added') ? 'checked' : 'unchecked'}`}
        onClick={() => toggleVisibleType('added')}
        style={{ cursor: 'pointer' }}
      >
        <div className="icon"></div>
        <span>新增 · {stats.added}</span>
      </div>
      
      <div 
        className={`stats-item removed ${visibleTypes.has('removed') ? 'checked' : 'unchecked'}`}
        onClick={() => toggleVisibleType('removed')}
        style={{ cursor: 'pointer' }}
      >
        <div className="icon"></div>
        <span>删除 · {stats.removed}</span>
      </div>
      
      <div 
        className={`stats-item moved ${visibleTypes.has('moved') ? 'checked' : 'unchecked'}`}
        onClick={() => toggleVisibleType('moved')}
        style={{ cursor: 'pointer' }}
      >
        <div className="icon"></div>
        <span>移动 · {stats.moved}</span>
      </div>
    </div>
  );

  // 简单的同步滚动处理
  const handleSyncScroll = (source: 'left' | 'right') => {
    if (syncingRef.current || !leftPanelRef.current || !rightPanelRef.current) return;
    
    syncingRef.current = true;
    const sourcePanel = source === 'left' ? leftPanelRef.current : rightPanelRef.current;
    const targetPanel = source === 'left' ? rightPanelRef.current : leftPanelRef.current;
    
    // 简单的比例同步 - 最稳定的方法
    const scrollRatio = sourcePanel.scrollTop / (sourcePanel.scrollHeight - sourcePanel.clientHeight || 1);
    targetPanel.scrollTop = scrollRatio * (targetPanel.scrollHeight - targetPanel.clientHeight);
    
    setTimeout(() => {
      syncingRef.current = false;
    }, 10);
  };

  // 渲染侧边对比视图
  const renderSideBySideView = () => {
    // 创建统一的行映射 - 左右两边显示相同的行，只是有些行为空
    // 修复：不基于undefined值过滤，因为undefined也是有效值需要显示
    const unifiedLines = processedLines
      .map(line => ({
        ...line,
        shouldShowInOld: line.type !== 'added',
        shouldShowInNew: line.type !== 'removed'
      }))
      // 只要这行有任何差异类型，都应该显示
      .filter(line => true); // 显示所有行

    return (
      <div className="side-by-side">
        <div className="diff-panel">
          <div className="panel-header old-value">旧值</div>
          <div 
            className="panel-content"
            ref={leftPanelRef}
            onScroll={() => handleSyncScroll('left')}
          >
            {unifiedLines.map((line, index) => 
              line.shouldShowInOld ? renderJsonLine(line, index + 1, 'old') : 
              <div key={`${line.id}-old-empty`} className="json-line empty" style={{ height: '32px' }}></div>
            )}
          </div>
        </div>
        
        <div className="diff-panel">
          <div className="panel-header new-value">新值</div>
          <div 
            className="panel-content"
            ref={rightPanelRef}
            onScroll={() => handleSyncScroll('right')}
          >
            {unifiedLines.map((line, index) => 
              line.shouldShowInNew ? renderJsonLine(line, index + 1, 'new') : 
              <div key={`${line.id}-new-empty`} className="json-line empty" style={{ height: '32px' }}></div>
            )}
          </div>
        </div>
      </div>
    );
  };

  // 渲染统一视图
  const renderUnifiedView = () => (
    <div className="unified-view">
      <div className="unified-header">JSON差异对比</div>
      <div className="panel-content">
        {processedLines.map((line, index) => renderJsonLine(line, index + 1))}
      </div>
    </div>
  );

  // 初始化时展开根级别属性
  useEffect(() => {
    const rootPaths = new Set<string>();
    diffs.forEach(diff => {
      if (diff.path.length === 1) {
        rootPaths.add(pathToString(diff.path));
      }
    });
    setExpandedPaths(rootPaths);
  }, [diffs]);

  return (
    <div className="json-diff-container">
      {renderStats()}
      
      <div className="diff-content">
        {viewMode === 'side-by-side' ? renderSideBySideView() : renderUnifiedView()}
      </div>
    </div>
  );
};

export default JsonDiffViewer; 